<template>
  <Dialog
    title="模型预览"
    width="1200px"
    @opened="handleOpened"
    @open="handleOpen"
    :has-footer="false"
  >
    <div v-loading="isLoading" class="container" ref="containerRef"></div>
  </Dialog>
</template>

<script setup lang="ts">
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { Ref, ref, shallowRef } from 'vue'

import Dialog from '@/components/Dialog/index.vue'

import useCsg from '../hooks/useCsg'

interface EmitsType {
  (e: 'opened'): void
}
const emits = defineEmits<EmitsType>()

const isLoading = ref(true)

const containerRef = ref<HTMLDivElement | undefined>(undefined)

const { intersect } = useCsg()
const { scene, camera, initThree } = useThree(containerRef)

const init = async () => {
  const model = intersect(catchModelA.value!, catchModelB.value!) as THREE.Mesh
  scene.value?.add(model)

  const bbox = new THREE.Box3().setFromObject(model)
  const size = bbox.getSize(new THREE.Vector3())
  camera.value?.position.set(0, 0, size.z * 2)
  camera.value?.lookAt(model.position)
  isLoading.value = false
  // addModel(model)
  console.log('end')
}

const catchModelA = shallowRef<THREE.Mesh | null>(null)
const catchModelB = shallowRef<THREE.Mesh | null>(null)
const setMesh = (modelA: THREE.Mesh, modelB: THREE.Mesh) => {
  catchModelA.value = modelA
  catchModelB.value = modelB
}

const handleOpened = () => {
  emits('opened')
}

const handleOpen = () => {
  initThree()
}

defineExpose({ init, setMesh })

function useThree(domRef: Ref<HTMLDivElement | undefined>) {
  const scene = shallowRef<THREE.Scene | null>(null)
  const camera = shallowRef<THREE.Camera | null>(null)
  const renderer = shallowRef<THREE.WebGLRenderer | null>(null)
  const controls = shallowRef<OrbitControls | null>(null)

  function animate() {
    renderer.value?.render(scene.value!, camera.value!)
  }
  const initThree = () => {
    if (!domRef.value) return
    scene.value = new THREE.Scene()
    camera.value = new THREE.PerspectiveCamera(
      75,
      domRef.value.offsetWidth / domRef.value.offsetHeight,
      0.1,
      10000,
    )
    const ambientLight = new THREE.AmbientLight(0xffffff, 1)
    scene.value.add(ambientLight)

    const pointLight = new THREE.PointLight(0xffffff, 1)
    camera.value.add(pointLight)

    controls.value = new OrbitControls(camera.value, domRef.value)
    controls.value.enableDamping = false
    controls.value.minDistance = 0.2

    renderer.value = new THREE.WebGLRenderer({ antialias: true, alpha: true })
    renderer.value.setPixelRatio(window.devicePixelRatio)
    renderer.value.setSize(domRef.value.offsetWidth, domRef.value.offsetHeight)
    renderer.value.setAnimationLoop(animate)
    domRef.value.appendChild(renderer.value.domElement)
    camera.value.position.z = 5
  }
  return {
    scene,
    camera,
    initThree,
  }
}
</script>

<style scoped lang="scss">
.container {
  height: 500px;
}
</style>
